﻿
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace HCLSMod.NetSocket
{
    /// <summary>
    /// 记录系统事件到日志中
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="EventType"></param>
    /// <param name="fErrorInfo"></param>
    public delegate void SystemEventLog(object sender, EventLogEntryType EventType, string fErrorInfo);

    public delegate void SocketEventCallBack(object sender, Socket ClientSocket);
    public delegate void SocketRecDataCallBack(object sender, Socket ClientSocket, ref byte[] RecData);

    public interface TCPServerInterface
    {
        string LocalIPAddress { get; set; }
        int LocalPort { get; set; }
        int OnlineCount { get; }
        string[] ClientEndPoints { get; }
        void StartListen();
        void StopListen();
        bool RemoveClient(TCPSerClientThread fClient);
        void OnRecDataEvent(object sender, Socket ClientSocket, ref byte[] RecData);
    }

    /// <summary>
    /// 服务器组件
    /// 注意：
    /// ClientsManagerEnable控制是否启动客户端列表维护
    /// </summary>
    public class TCPServerSocket : ZLErrorRecord, TCPServerInterface
    {
        #region 成员
        protected Socket fTCPServer { get; set; }
        protected Thread fListenThd { get; set; }
        protected bool fListenRun { get; set; }

        protected string fNetAddress = "127.0.0.1";
        protected int fNetPort = 9848;

        public int Backlog { get; set; }

        /// <summary>
        /// 是否启动客户端列表维护
        /// </summary>
        private bool bCliMEnable = false;
        /// <summary>
        /// 是否启动客户端列表维护
        /// </summary>
        public bool ClientsManagerEnable
        {
            get { return bCliMEnable; }
            set
            {
                bCliMEnable = value;
                if (value)
                {
                    // 启动客户端在线监测线程
                    Thread THDClientOnLine = new Thread(ThdClientsManager);
                    THDClientOnLine.Start();
                }
                else
                    Thread.Sleep(1);
            }
        }
        /// <summary>
        /// 客户端在线超时，单位：s
        /// </summary>
        private int iCliSleepTimeOut = 10;
        /// <summary>
        /// 客户端在线超时，单位：s。最小时长3s
        /// </summary>
        public int ClientSleepTimeOut
        {
            get { return iCliSleepTimeOut; }
            set
            {
                if (value < 3)
                    iCliSleepTimeOut = 3;
                else
                    iCliSleepTimeOut = value;
            }
        }
        /// <summary>
        /// 客户端列表
        /// </summary>
        protected Dictionary<string, TCPSerClientThread> dTCPClients { get; set; }
        /// <summary>
        /// 线程锁
        /// </summary>
        private Mutex MutexClientsThd = new Mutex(false, "MutexClientsManger:" + Guid.NewGuid().ToString());

        public event SocketEventCallBack OnConnect = null;
        public event SocketEventCallBack OnDisconnect = null;
        public event SocketEventCallBack AfterDisconnect = null;
        public event SocketRecDataCallBack OnReceive = null;
        public event SystemEventLog OnEventLog = null;

        /// <summary>
        /// 监听地址
        /// </summary>
        public string LocalIPAddress
        {
            get
            {
                return fNetAddress;
            }
            set
            {
                fNetAddress = value;
            }
        }

        /// <summary>
        /// 监听端口
        /// </summary>
        public int LocalPort
        {
            get
            {
                return fNetPort;
            }
            set
            {
                fNetPort = value;
            }
        }
        /// <summary>
        /// 监听点信息
        /// </summary>
        public IPEndPoint LocalIPEndPoint
        {
            get
            {
                IPAddress fLocalIP;
                if ((IPAddress.TryParse(fNetAddress, out fLocalIP))
                    && (fNetPort > 0) && (fNetPort < 0x10000))
                {
                    IPEndPoint fIPEndPoint = new IPEndPoint(fLocalIP, fNetPort);
                    return fIPEndPoint;
                }
                else
                    return null;
            }
        }
        /// <summary>
        /// 服务器是否在运行
        /// </summary>
        public bool SerActive
        {
            get
            {
                if (fListenThd != null)
                    return fListenThd.IsAlive;
                else
                    return false;
            }
        }
        /// <summary>
        /// 当前连接到服务器的客户数量
        /// </summary>
        public int OnlineCount { get { return dTCPClients.Count; } }
        /// <summary>
        /// 连接到服务器的全部客户的IPEndPoint
        /// </summary>
        public string[] ClientEndPoints
        {
            get
            {
                MutexClientsThd.WaitOne();
                try
                {
                    return dTCPClients.Keys.ToArray();
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
        }


        #endregion

        /// <summary>
        /// 获取本机IP， 静态函数
        /// </summary>
        /// <returns></returns>
        public static IPAddress getIpAddress()
        {
            //获取本地的IP地址
            string AddressIP = string.Empty;
            IPAddress ip = null;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                    ip = _IPAddress;
                }
            }
            return ip;
        }

        public static IPAddress[] getIpAddressList()
        {
            //获取本地的IP地址
            List<IPAddress> IPList = new List<IPAddress>();
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    IPList.Add(_IPAddress);
                }
            }
            return IPList.ToArray();
        }

        #region 构建函数，守护线程

        private TCPServerSocket()
        {
            Backlog = 250;
            dTCPClients = new Dictionary<string, TCPSerClientThread>();
            ClientsManagerEnable = true;
        }
        /// <summary>
        /// 自动绑定当前系统所有IP地址
        /// </summary>
        /// <param name="fSerPort"></param>
        public TCPServerSocket(int fSerPort) : this()
        {
            fNetAddress = IPAddress.Any.ToString();
            fNetPort = fSerPort;
            try
            {
                fTCPServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                fTCPServer.Bind(new IPEndPoint(IPAddress.Any, fNetPort));
            }
            catch (Exception ex)
            {
                PutErrorEvent(ex);
                OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
            }
        }
        /// <summary>
        /// 仅绑定指定IP地址
        /// </summary>
        /// <param name="fSerIPAddress"></param>
        /// <param name="fSerPort"></param>
        public TCPServerSocket(IPAddress fSerIPAddress, int fSerPort) : this()
        {
            fNetAddress = fSerIPAddress.ToString();
            fNetPort = fSerPort;
            try
            {
                fTCPServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                fTCPServer.Bind(new IPEndPoint(IPAddress.Parse(fNetAddress), fNetPort));
            }
            catch (Exception ex)
            {
                PutErrorEvent(ex);
                OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
            }
        }
        /// <summary>
        /// 监测客户是否在线
        /// </summary>
        private void ThdClientsManager()
        {
            while (bCliMEnable)
            {
                MutexClientsThd.WaitOne();
                try
                {
                    string sTimeOutClientEP = "";
                    if (dTCPClients.Count > 0)
                        do
                        {
                            sTimeOutClientEP = null;
                            foreach (string sCliEP in dTCPClients.Keys)
                            {
                                // 判断客户端最后在线时间
                                TimeSpan tSleepPass = DateTime.Now - dTCPClients[sCliEP].LastAction;
                                if ((tSleepPass.TotalSeconds > ClientSleepTimeOut)
                                    || (!dTCPClients[sCliEP].Connected))
                                {
                                    sTimeOutClientEP = sCliEP;
                                    break;
                                }
                            }
                            // 发现超时，删除对象
                            if (!string.IsNullOrEmpty(sTimeOutClientEP))
                            {
                                if (dTCPClients.ContainsKey(sTimeOutClientEP))
                                {
                                    dTCPClients[sTimeOutClientEP].Stop();
                                    dTCPClients.Remove(sTimeOutClientEP);
                                }
                            }
                        } while (!string.IsNullOrEmpty(sTimeOutClientEP));
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
                Thread.Sleep(1);
            }
        }
        #endregion

        /// <summary>
        /// 开始监听
        /// </summary>
        public void StartListen()
        {
            try
            {
                if (Backlog > 0)
                    fTCPServer.Listen(Backlog);
                else
                    fTCPServer.Listen(250);

                fListenRun = true;
                fListenThd = new Thread(new ThreadStart(Listen));
                fListenThd.Name = "服务器监听线程";
                fListenThd.Start();
            }
            catch (Exception ex)
            {
                PutErrorEvent(ex);
                OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
            }
        }

        /// <summary>
        /// 停止监听
        /// </summary>
        public void StopListen()
        {
            try
            {
                fListenRun = false;
                fListenThd = null;

                if (fTCPServer != null)
                    fTCPServer.Close();
                MutexClientsThd.WaitOne();
                try
                {
                    foreach (string sClientEP in dTCPClients.Keys)
                        dTCPClients[sClientEP].Stop();
                    dTCPClients.Clear();
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
                ClientsManagerEnable = false;
            }
            catch (Exception ex)
            {
                PutErrorEvent(ex);
                OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
            }
        }
        /// <summary>
        /// 向指定的从机发送数据，从机必须已经连接
        /// </summary>
        /// <param name="fData"></param>
        /// <param name="fDestIPEndPoint"></param>
        /// <returns>已经发送的数据字节数</returns>
        public int Sendbytes(byte[] fData, string fDestIPEndPoint)
        {
            if (ClientsManagerEnable)
            {
                MutexClientsThd.WaitOne();
                try
                {
                    if (dTCPClients.ContainsKey(fDestIPEndPoint))
                    {
                        SetTxRecord(new ZLByteDataRecord(fData, fDestIPEndPoint));
                        return dTCPClients[fDestIPEndPoint].SendBytes(fData);
                    }
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
            return 0;
        }

        public int Sendbytes(byte[] fData, IPEndPoint fDestIPEndPoint)
        {
            return Sendbytes(fData, fDestIPEndPoint.ToString());
        }
        #region 监听管理

        /// <summary>
        /// 移除某个客户端
        /// </summary>
        /// <param name="fClient"></param>
        public int AddClient(TCPSerClientThread fClient)
        {
            if (ClientsManagerEnable)
            {
                MutexClientsThd.WaitOne();
                try
                {
                    IPEndPoint tDestIPEndPoint = fClient.RemoteIP;
                    if ((tDestIPEndPoint != null) &&
                        (!dTCPClients.ContainsKey(tDestIPEndPoint.ToString())))
                    {
                        dTCPClients.Add(tDestIPEndPoint.ToString(), fClient);
                        return dTCPClients.Count;
                    }
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
            return -1;
        }

        /// <summary>
        /// 移除某个客户端
        /// </summary>
        /// <param name="fClient"></param>
        public bool RemoveClient(TCPSerClientThread fClient)
        {
            if (ClientsManagerEnable)
            {
                MutexClientsThd.WaitOne();
                try
                {
                    IPEndPoint tDestIPEndPoint = fClient.RemoteIP;
                    if ((tDestIPEndPoint != null) &&
                        dTCPClients.ContainsKey(tDestIPEndPoint.ToString()))
                    {
                        dTCPClients.Remove(tDestIPEndPoint.ToString());
                        return true;
                    }
                }
                finally
                {
                    MutexClientsThd.ReleaseMutex();
                }
            }
            return false;
        }

        /// <summary>
        /// 监听线程
        /// </summary>
        protected void Listen()
        {
            while (fListenRun)
            {
                try
                {
                    Socket fClientSocket = fTCPServer.Accept();
                    TCPSerClientThread fClientThread = new TCPSerClientThread(this, fClientSocket);
                    fClientThread.OnDisconnect += OnDisconnect;
                    fClientThread.AfterDisconnect += AfterDisconnect;
                    fClientThread.OnEventLog += this.OnEventLog;
                    fClientThread.OnResponRequest += FClientThread_OnResponRequest;
                    AddClient(fClientThread);
                    OnConnect?.Invoke(this, fClientSocket);
                    fClientThread.Start();
                }
                catch (Exception ex)
                {
                    PutErrorEvent(ex);
                    OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
                    break;
                }
            }
            StopListen();
        }

        private void FClientThread_OnResponRequest(object sender, Socket ClientSocket, ref byte[] RecData)
        {
            SetTxRecord(new ZLByteDataRecord(RecData, ClientSocket.RemoteEndPoint.ToString()));
        }
        #endregion

        public virtual void OnRecDataEvent(object sender, Socket ClientSocket, ref byte[] RecData)
        {
            SetRxRecord(new ZLByteDataRecord(RecData, ClientSocket.RemoteEndPoint.ToString()));
            OnReceive?.Invoke(sender, ClientSocket, ref RecData);
        }
    }

    /// <summary>
    /// 用于服务器处理每个客户端的线程
    /// </summary>
    public class TCPSerClientThread : ZLErrorRecord
    {
        public Socket fClientSocket { get; set; }
        protected Thread fClientThd { get; set; }
        protected TCPServerInterface fSerSocket { get; set; }

        public event SocketEventCallBack OnDisconnect = null;
        public event SocketEventCallBack AfterDisconnect = null;
        public event SystemEventLog OnEventLog = null;
        public event SocketRecDataCallBack OnResponRequest = null;

        public object Tag { get; set; }

        public bool Connected { get { return (fClientSocket != null) && fClientSocket.Connected; } }

        public string RemoteAddress { get { return fClientSocket.RemoteEndPoint.ToString(); } }

        public IPEndPoint RemoteIP
        {
            get
            {
                if (fClientSocket != null)
                    return (IPEndPoint)fClientSocket.RemoteEndPoint;
                else
                    return null;
            }
        }

        public DateTime LastAction { get; set; }

        public TCPSerClientThread(TCPServerInterface fServerX, Socket fClientX)
        {
            LastAction = DateTime.Now;
            this.fSerSocket = fServerX;
            fClientSocket = fClientX;
        }

        /// <summary>
        /// 开始客户线程
        /// </summary>
        public void Start()
        {
            fClientThd = new Thread(new ThreadStart(StartThread));
            fClientThd.Name = "客户线程";
            fClientThd.Start();
        }
        /// <summary>
        /// 停止客户线程
        /// </summary>
        public void Stop()
        {
            try
            {
                if (fClientThd != null)
                {
                    fClientThd.Abort();
                    fClientThd = null;
                }
                fClientSocket.Shutdown(SocketShutdown.Both);
                fClientSocket.Close();
            }
            catch (Exception ex)
            {
                PutErrorEvent(ex);
                OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
            }
        }

        private void StartThread()
        {
            byte[] buffer = new byte[1024];
            while (true)
            {
                try
                {
                    int fRecCount = 0;
                    fRecCount = fClientSocket.Receive(buffer, SocketFlags.Peek);
                    //fRecCount = fClientSocket.Available;
                    if (fRecCount != 0)
                    {
                        this.LastAction = DateTime.Now;
                        if (fSerSocket != null)
                        {
                            byte[] fRecbuf = new byte[fRecCount];
                            fClientSocket.Receive(fRecbuf, SocketFlags.None);
                            fSerSocket.OnRecDataEvent(this, fClientSocket, ref fRecbuf);
                            if ((fRecbuf != null) && (fRecbuf.Length > 0))
                            {
                                fClientSocket.Send(fRecbuf, 0, fRecbuf.Length, SocketFlags.None);
                                if (OnResponRequest != null)
                                    OnResponRequest(this, fClientSocket, ref fRecbuf);
                            }
                        }
                    }
                    else
                    {
                        OnDisconnect?.Invoke(this, fClientSocket);
                        fClientSocket.Close();
                        if (fSerSocket != null)
                            fSerSocket.RemoveClient(this);
                        AfterDisconnect?.Invoke(this, fClientSocket);
                        break;
                    }
                }
                catch (Exception ex)
                {
                    PutErrorEvent(ex);
                    OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
                    break;
                }
                Thread.Sleep(1);
            }
        }

        public int SendBytes(byte[] fSendData)
        {
            try
            {
                this.LastAction = DateTime.Now;
                if ((fClientSocket != null) && (fClientSocket.Connected))
                    return fClientSocket.Send(fSendData, 0, fSendData.Length, SocketFlags.None);
                else
                {
                    if (fSerSocket != null)
                        fSerSocket.RemoveClient(this);
                    AfterDisconnect?.Invoke(this, fClientSocket);
                }
            }
            catch (Exception ex)
            {
                PutErrorEvent(ex);
                OnEventLog?.Invoke(this, EventLogEntryType.Error, ex.Message);
            }
            return 0;
        }

        public int Poll()
        {
            this.LastAction = DateTime.Now;
            if (fClientSocket.Poll(-1, SelectMode.SelectRead))
            {
                byte[] buffer = new byte[1024];
                return fClientSocket.Receive(buffer, SocketFlags.Peek);
            }
            else
                return -1;
        }
    }
}
